Link to this headingTypes of Hashes

How they work

Test Hashes:

import hashlib, sys, os, hmac from Crypto.Cipher import DES def expand_DES_key(key): # Expand the key from a 7-byte password key into a 8-byte DES key if not isinstance(key, bytes): key = bytes(key, encoding='utf8') key = bytearray(key[:7]).ljust(7, b'\x00') s = bytearray() s.append(((key[0] >> 1) & 0x7f) << 1) s.append(((key[0] & 0x01) << 6 | ((key[1] >> 2) & 0x3f)) << 1) s.append(((key[1] & 0x03) << 5 | ((key[2] >> 3) & 0x1f)) << 1) s.append(((key[2] & 0x07) << 4 | ((key[3] >> 4) & 0x0f)) << 1) s.append(((key[3] & 0x0f) << 3 | ((key[4] >> 5) & 0x07)) << 1) s.append(((key[4] & 0x1f) << 2 | ((key[5] >> 6) & 0x03)) << 1) s.append(((key[5] & 0x3f) << 1 | ((key[6] >> 7) & 0x01)) << 1) s.append((key[6] & 0x7f) << 1) return bytes(s) def DES_block(key, msg): key = expand_DES_key(key) cipher = DES.new(key,DES.MODE_ECB) return cipher.encrypt(msg) def NT(password): return hashlib.new("md4", password.encode('utf_16le')).digest() def NTLMv2(input_hash, user_name, domain_name): return hmac.new(input_hash, user_name + domain_name, "md5").digest() def LM(password): password = password.upper() lmhash = DES_block(password[:7], b"KGS!@#$%") lmhash += DES_block(password[7:14], b"KGS!@#$%") return lmhash if __name__ == '__main__': #server_challenge = os.urandom(8) server_challenge = b"\x01\x23\x45\x67\x89\xab\xcd\xef" client_challenge = b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" domain_name = "Domain" user_name = "User" password = "Password" server_name = b"Server" #server_name = b'\x02\x00\x0c\x00\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00\x01\x00\x0c\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x00\x00\x00\x00' nt_hash = NT(password) lm_hash = LM(password) ### Local Hashes print("Password: {}".format(password)) print("Server Nonce: {}".format(server_challenge.hex())) print("NT Hash: {}".format(nt_hash.hex())) print("LM Hash: {}\n".format(lm_hash.hex())) ### Version 1 Net Hashes nt_response = DES_block(nt_hash[:7], server_challenge) + DES_block(nt_hash[7:14], server_challenge) + DES_block(nt_hash[14:], server_challenge) lm_response = DES_block(lm_hash[:7], server_challenge) + DES_block(lm_hash[7:14], server_challenge) + DES_block(lm_hash[14:], server_challenge) print("Net-NTv1 Response: {}".format(nt_response.hex())) print("Net-LMv1 Response: {}".format(lm_response.hex())) shared_key = hashlib.new("md4", nt_hash).digest() print("Net-NTLMv1 Shared Key: {}\n".format(shared_key.hex())) ### Version 2 Net Hashes nt_response_key_v2 = NTLMv2(nt_hash, user_name.upper().encode('utf_16le'), domain_name.encode('utf_16le')) lm_response_key_v2 = NTLMv2(lm_hash, user_name.upper().encode('utf_16le'), domain_name.encode('utf_16le')) # Response Server Version + \x00\x00\x00\x00\x00\x00 + Time Stamp + Client Challenge + \x00\x00\x00\x00 + server_name + \x00\x00\x00\x00 temp = b'\x01\x01' + b'\x00' * 6 + b'\x00' * 8 + client_challenge + b'\x00' * 4 + server_name + b'\x00' * 4 temp_response = NTLMv2(nt_response_key_v2, server_challenge, temp) nt_response_v2 = temp_response + temp lm_response_v2 = NTLMv2(nt_response_key_v2, server_challenge, client_challenge) + client_challenge shared_key_v2 = NTLMv2(nt_response_key_v2, temp_response, b"") + b"" print("Net-NTv2 Response Key: {}".format(nt_response_key_v2.hex())) print("Net-LMv2 Response Key: {}".format(lm_response_key_v2.hex())) print("Net-NTv2 Response: {}".format(nt_response_v2.hex())) print("Net-LMv2 Response: {}".format(lm_response_v2.hex())) print("Net-NTLMv2 Shared Key: {}".format(shared_key_v2.hex())) #Verify asserts from https://github.com/SecureAuthCorp/impacket/blob/429f97a894d35473d478cbacff5919739ae409b4/tests/SMB_RPC/test_ntlm.py assert(lm_hash == bytearray(b'\xe5,\xacgA\x9a\x9a"J;\x10\x8f?\xa6\xcbm')) assert(nt_hash == bytearray(b'\xa4\xf4\x9c\x40\x65\x10\xbd\xca\xb6\x82\x4e\xe7\xc3\x0f\xd8\x52')) assert(nt_response == bytearray(b'\x67\xC4\x30\x11\xF3\x02\x98\xA2\xAD\x35\xEC\xE6\x4F\x16\x33\x1C\x44\xBD\xBE\xD9\x27\x84\x1F\x94')) assert(lm_response == bytearray(b'\x98\xDE\xF7\xB8\x7F\x88\xAA\x5D\xAF\xE2\xDF\x77\x96\x88\xA1\x72\xde\xf1\x1c\x7d\x5c\xcd\xef\x13')) assert(shared_key == bytearray(b'\xD8\x72\x62\xB0\xCD\xE4\xB1\xCB\x74\x99\xBE\xCC\xCD\xF1\x07\x84')) assert(nt_response_key_v2==bytearray(b'\x0c\x86\x8a\x40\x3b\xfd\x7a\x93\xa3\x00\x1e\xf2\x2e\xf0\x2e\x3f')) assert(lm_response_key_v2==bytearray(b'\xc2\xd6\x9a\xca\xe7\x12\x59\xa9\xc7\xcd\x95\x81\x63\xa9\x8b\x1c')) assert(nt_response_v2[:16]==bytearray(b'\x35\x6c\x72\x25\x90\x7b\x92\x6d\x1b\xac\xf4\x0a\x41\x77\xe0\x58')) assert(lm_response_v2==bytearray(b'\x86\xc3\x50\x97\xac\x9c\xec\x10\x25\x54\x76\x4a\x57\xcc\xcc\x19\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa')) assert(shared_key_v2==bytearray(b'\x8e\x63\xba\x6e\x5f\x82\x76\x30\xca\xaf\x3e\xc7\xa8\x9b\xd8\xa8'))

Link to this headingLM Hashes

  • case-insensitive
  • limited character set of only 142 characters
  • splits the password into two 7-character chunks
    • padding as necessary.
  • LM was turned off by default starting in Windows Vista/Server 2008
  • supports Pass the Hash

How the password is hashed:

  1. Convert all lower case to upper case
  2. Pad password to 14 characters with NULL characters
  3. Split the password to two 7 character chunks
  4. Create two [DES](/Crypto/Symmetric Encryption/DES) keys from each 7 character chunk
  5. DES encrypt the string “KGS!@#$%” with these two chunks
  6. Concatenate the two DES encrypted strings. This is the LM hash.

Example of a LM Hash:
299BD128C1101FD6

Cracking Hashes

john --format=lm hash.txt hashcat -m 3000 -a 3 hash.txt

Link to this headingNTHash (A.K.A. NTLM)

This is the way passwords are stored on modern Windows systems, and can be obtained by dumping the SAM database, or using Mimikatz. They are also stored on domain controllers in the NTDS file. These are the hashes you can use to pass-the-hash.

  • case-sensitive
  • supports almost the entire Unicode character set of 65,536 characters
  • NT hash calculates the hash based on the entire password the user entered
  • supports Pass the Hash

How the password is hashed:

def NT(password): return hashlib.new("md4", password.encode('utf_16le')).digest()

Example of a NTHash:
B4B9B02E6F09A9BD760F388B67351E2B

Cracking Hashes

john --format=nt hash.txt hashcat -m 1000 -a 3 hash.txt

Link to this headingNTLMv1 (A.K.A. Net-NTLMv1)

  • Can use either the NT or LM hash
  • does not support Pass the Hash
  • Can be relayed to other servers if SMB Signing is disabled
    • Can also be relayed back to the same server if does not have patch (MS08-068)
      • Can relay cross-protocol if has patch

The NTLM protocol uses the NTHash in a challenge/response between a server and a client. The v1 of the protocol uses both the NT and LM hash, depending on configuration and what is available.

How the password is hashed:

#C = 8-byte server challenge, random C = os.urandom(8) #Generate a NT hash nt_hash = generate_NT_Hash(password) #Generate a LM hash with up to 14 char password lm_hash = generate_LM_Hash(password) #Pad the key #Similar to the LM hash use the hash as the key for encrypting the server challenge lm_response = DES_block(lm_hash[:7], C) + DES_block(lm_hash[:7:14], C) + DES_block(lm_hash[14:], C) nt_response = DES_block(nt_hash[:7], C) + DES_block(nt_hash[:7:14], C) + DES_block(nt_hash[14:], C) #K1 | K2 | K3 = LM/NT-hash | 5-bytes-0 combined_key = nt_hash + "\x00\x00\x00\x00\x00\x00" key1, key2, key3 = combined_key response = DES(K1,C) | DES(K2,C) | DES(K3,C)

Example:
u4-netntlm::kNS:338d08f8e26de93300000000000000000000000000000000:9526fb8c23a90751cdd619b6cea564742e1e4bf33006ba41:cb8086049ec4736c

Cracking Hashes
john --format=netntlm hash.txt
hashcat -m 5500 -a 3 hash.txt

Link to this headingNTLMv2 (A.K.A. Net-NTLMv2)

This is the new and improved version of the NTLM protocol, which makes it a bit harder to crack. The concept is the same as NTLMv1, only different algorithm and responses sent to the server. Also captured through [Responder](/Red Team/Responder.md) or similar. Default in Windows since Windows 2000.

Example:
admin::N46iSNekpT:08ca45b7d7ea58ee:88dcbe4446168966a153a0064958dac6:5c7830315c7830310000000000000b45c67103d07d7b95acd12ffa11230e0000000052920b85f78d013c31cdb3b92f5d765c783030

Algorithm

SC = 8-byte server challenge, random CC = 8-byte client challenge, random CC* = (X, time, CC2, domain name) v2-Hash = HMAC-MD5(NT-Hash, user name, domain name) LMv2 = HMAC-MD5(v2-Hash, SC, CC) NTv2 = HMAC-MD5(v2-Hash, SC, CC*) response = LMv2 | CC | NTv2 | CC*

Cracking Hashes

john --format=netntlmv2 hash.txt hashcat -m 5600 -a 3 hash.txt

Different Windows Hashes

Link to this headingRelaying Hashes

Relaying hashes back to the same machine wont work with the MS08-068 update. It is possible to do so in a cross-protocol relay attack.
It is possible to relay the hash to another machine.

This is only possible with SMB signing turned off which is default except for Windows Server OS’s.